package com.tianyalei.gateway.gatewayauth.tool;

import org.springframework.cloud.gateway.route.Route;
import org.springframework.cloud.gateway.route.RouteLocator;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.util.StringUtils;
import reactor.core.publisher.Flux;
import java.util.Arrays;
import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.Collectors;

/**
 * zuul的路由规则工具类
 * @author wuweifeng wrote on 2019-08-19.
 * update by liyunfeng 2020-1-14
 */
public class RouteLocatorUtil {

    /**
     * 解析出该请求是请求的哪个微服务
     */
    public static String[] parseAppNameAndPath(RouteLocator routeLocator, ServerHttpRequest serverHttpRequest) {
        return parseAppNameAndPath(routeLocator, serverHttpRequest.getURI().toASCIIString());
    }

    public static String[] parseAppNameAndPath(RouteLocator routeLocator, String requestPath) {
        String[] array = new String[2];
        //一个requestPath：//类似于  /zuuldmp/core/test。其中/zuuldmp是zuul的prefix，core是微服务的名字
        //获取所有路由信息，找到该请求对应的appName
        // 一个Route信息如：Route{id='one', fullPath='/zuuldmp/auth/**', path='/**', location='auth', prefix='/zuuldmp/auth',
        Flux<Route> routeList = routeLocator.getRoutes();
        AtomicReference<String> appName= new AtomicReference<>("");
        AtomicReference<String> path = new AtomicReference<>("");
        routeList.takeWhile(
                route ->
                    requestPath.startsWith(String.format("/%s", Arrays.stream(StringUtils.
                        tokenizeToStringArray(route.getUri().getPath(), "/")).findFirst().get())))
                .subscribe(route -> {
                    appName.set(route.getId());
                    //具体的微服务里面的请求路径，如 /test
                    path.set(String.format("/%s", Arrays.stream(StringUtils.
                          tokenizeToStringArray(route.getUri().getPath(),"/"))
                         .skip(1).collect(Collectors.joining("/"))));  // config.part 默认为1了
                });
        array[0] = appName.get();
        array[1] = path.get();
        return array;
    }

    public static class Config {
        private int parts;

        public int getParts() {
            return parts;
        }

        public void setParts(int parts) {
            this.parts = parts;
        }
    }
}
